package com.chukun.gateway.client.support.http;

import com.chukun.gateway.client.properties.ApiProperties;
import com.chukun.gateway.client.scanner.ApiAnnotationScanner;
import com.chukun.gateway.client.support.AbstractClientRegisterManager;
import com.chukun.gateway.common.definition.ServiceDefinition;
import com.chukun.gateway.common.instance.ServiceInstance;
import com.chukun.gateway.common.utils.NetUtils;
import com.chukun.gateway.common.utils.TimeUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static com.chukun.gateway.common.constants.GatewayCommonConst.COLON_SEPARATOR;
import static com.chukun.gateway.common.constants.GatewayConst.DEFAULT_WEIGHT;

/**
 * @author chukun
 * @version 1.0.0
 * @description springmvc客户端
 * @createTime 2023/11/26 21:48
 */
@Slf4j
public class SpringMVCClientRegisterManager extends AbstractClientRegisterManager implements ApplicationContextAware, ApplicationListener<ApplicationEvent> {

    private ApplicationContext applicationContext;

    @Resource
    private ServerProperties serverProperties;

    private Set<Object> existsBeans = new HashSet<>();

    public SpringMVCClientRegisterManager(ApiProperties apiProperties) {
        super(apiProperties);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        if (applicationEvent instanceof ApplicationStartedEvent) {
            try {
                doRegisterSpringMvc();
            } catch (Exception e) {
                log.error("SpringMVCClientRegisterManager.doRegisterSpringMvc error", e);
                throw new RuntimeException(e);
            }
            log.info("SpringMVCClientRegisterManager.doRegisterSpringMvc api started");
        }
    }

    /**
     * 注册springmvc
     */
    private void doRegisterSpringMvc() {
        Map<String, RequestMappingHandlerMapping> handlerMapping =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RequestMappingHandlerMapping.class, true, false);
        if (MapUtils.isEmpty(handlerMapping)) {
            return;
        }
        for (RequestMappingHandlerMapping mapping : handlerMapping.values()) {
            Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
            if (MapUtils.isEmpty(handlerMethods)) {
                continue;
            }
            for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
                HandlerMethod handlerMethod = entry.getValue();
                Class<?> beanClazz = handlerMethod.getBeanType();
                Object bean = applicationContext.getBean(beanClazz);
                if (existsBeans.contains(bean)) {
                    continue;
                }
                ServiceDefinition serviceDefinition = ApiAnnotationScanner.getInstance().scanner(bean);
                if (serviceDefinition == null) {
                    continue;
                }
                serviceDefinition.setEnvType(getApiProperties().getEnv());

                //服务实例
                ServiceInstance serviceInstance = new ServiceInstance();
                String localIp = NetUtils.getLocalIp();
                int port = serverProperties.getPort();
                String serviceInstanceId = localIp + COLON_SEPARATOR + port;
                String uniqueId = serviceDefinition.getUniqueId();
                String version = serviceDefinition.getVersion();

                serviceInstance.setServiceInstanceId(serviceInstanceId);
                serviceInstance.setUniqueId(uniqueId);
                serviceInstance.setIp(localIp);
                serviceInstance.setPort(port);
                serviceInstance.setRegisterTime(TimeUtils.currentTimeMillis());
                serviceInstance.setVersion(version);
                serviceInstance.setWeight(DEFAULT_WEIGHT);
                if (getApiProperties().isGray()) {
                    serviceInstance.setGray(true);
                }
                //注册
                register(serviceDefinition, serviceInstance);
            }
        }
    }
}
